﻿// ===============================================================================
// XCI.NET 西安交通信息WinForm开发框架 2018 版权所有
// ===============================================================================
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using XCI.Helper;

namespace XCI.Logger
{
    /// <summary>
    /// 日志实现基类
    /// </summary>
    public abstract class BaseLogger : ILogger
    {
        /// <summary>
        /// 变量正则对象
        /// </summary>
        public static readonly Regex VariableRegex = new Regex("({)([^}]+)(})", RegexOptions.Compiled);

        /// <summary>
        /// 输出级别
        /// </summary>
        public LoggerLevel Level { get; set; }
         
        /// <summary>
        /// 记录调试消息
        /// </summary>
        /// <param name="message">消息内容</param>
        /// <param name="tag">日志标签</param>
        public void Debug(string message, string tag = null)
        {
            Log(LoggerLevel.Debug, message, tag);
        }

        /// <summary>
        /// 记录普通消息
        /// </summary>
        /// <param name="message">消息内容</param>
        /// <param name="tag">日志标签</param>
        public void Info(string message, string tag = null)
        {
            Log(LoggerLevel.Info, message, tag);
        }

        /// <summary>
        /// 记录警告消息
        /// </summary>
        /// <param name="message">消息内容</param>
        /// <param name="tag">日志标签</param>
        public void Warn(string message, string tag = null)
        {
            Log(LoggerLevel.Warn, message, tag);
        }

        /// <summary>
        /// 记录错误消息
        /// </summary>
        /// <param name="message">消息内容</param>
        /// <param name="tag">日志标签</param>
        public void Error(string message, string tag = null)
        {
            Log(LoggerLevel.Error, message, tag);
        }

        /// <summary>
        /// 记录错误消息
        /// </summary>
        /// <param name="level">输出级别</param>
        /// <param name="message">消息内容</param>
        /// <param name="tag">日志标签</param>
        public void Log(LoggerLevel level, string message, string tag = null)
        {
            if (!IsEnabled(level)) return;

            var info = BuildLogInfo(level, message, tag);
            LogCore(info);
        }

        /// <summary>
        /// 测试指定的日志级别是否输出
        /// </summary>
        /// <param name="level">日志级别</param>
        protected bool IsEnabled(LoggerLevel level)
        {
            return level >= this.Level;
        }

        /// <summary>
        /// 获取日志数据对象
        /// </summary>
        /// <param name="level">日志级别</param>
        /// <param name="message">消息内容</param>
        /// <param name="tag">标签</param>
        protected LoggerInfo BuildLogInfo(LoggerLevel level, string message, string tag)
        {
            LoggerInfo logInfo = new LoggerInfo();
            logInfo.Level = level;
            logInfo.Tag = tag;
            logInfo.Message = message;
            logInfo.CreateDateTime = DateTime.Now;
            logInfo.CreateDate = DateTime.Now.Date;
            SetOccurMethodInfo(logInfo);
            return logInfo;
        }

        /// <summary>
        /// 变量转换
        /// </summary>
        /// <param name="tpl">模板</param>
        /// <param name="func">回调函数</param>
        /// <returns>返回替换后的字符串</returns>
        protected string CastVariable(string tpl, Func<string, string> func)
        {
            var tmp = VariableRegex.Replace(tpl, m =>
            {
                var v = m.Value.Substring(1, m.Value.Length - 2);
                return func(v);
            });
            return tmp;
        }

        /// <summary>
        /// 转换日志信息
        /// </summary>
        /// <param name="tpl">模板</param>
        /// <param name="info">日志信息</param>
        /// <returns>返回日志信息</returns>
        protected string CastLogInfo(string tpl, LoggerInfo info)
        {
            var tmp = CastVariable(tpl, v =>
             {
                 if (v.Equals("CreateDateTime", StringComparison.OrdinalIgnoreCase))
                 {
                     return DateTimeHelper.FormatDateHasSecond(DateTime.Now);
                 }
                 if (v.Equals("LogLevel", StringComparison.OrdinalIgnoreCase))
                 {
                     return info.Level.ToString();
                 }
                 if (v.Equals("Tag", StringComparison.OrdinalIgnoreCase))
                 {
                     return info.Tag;
                 }
                 if (v.Equals("CallClass", StringComparison.OrdinalIgnoreCase))
                 {
                     return info.ClassName;
                 }
                 if (v.Equals("CallMethod", StringComparison.OrdinalIgnoreCase))
                 {
                     return info.MethodName;
                 }
                 if (v.Equals("Message", StringComparison.OrdinalIgnoreCase))
                 {
                     return info.Message;
                 }
                 return v;
             });
            return tmp;
        }

        /// <summary>
        /// 获取写日志所在的方法
        /// </summary>
        protected virtual void SetOccurMethodInfo(LoggerInfo info)
        {
            var method = new StackTrace().GetFrame(5).GetMethod();
            if (method == null) return;
            info.MethodName = method.Name;
            if (method.DeclaringType != null)
            {
                info.ClassName = method.DeclaringType.FullName;
            }
        }

        /// <summary>
        /// 日志实现
        /// </summary>
        /// <param name="info">日志消息</param>
        protected abstract void LogCore(LoggerInfo info);
    }
}
